package com.elong.qadev.compiler;
 
import javax.tools.*;

import java.util.ArrayList;
import java.util.List;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.File;
import java.io.IOException;
/**
 * 
* @ClassName: DynamicEngine
* @Description: TODO(动态编译引擎)
* @author kangchen
* @date 2015年10月15日
*
 */
public class DynamicEngine {
    private static DynamicEngine ourInstance = new DynamicEngine();
 
    public static DynamicEngine getInstance() {
        return ourInstance;
    }
    private URLClassLoader parentClassLoader;
    private String classpath;
    private DynamicEngine() {
        this.parentClassLoader = (URLClassLoader) this.getClass().getClassLoader();
        this.buildClassPath();
    }
    private void buildClassPath() {
        this.classpath = null;
        StringBuilder sb = new StringBuilder();
        for (URL url : this.parentClassLoader.getURLs()) {
            String p = url.getFile();
            sb.append(p).append(File.pathSeparator);
        }
        this.classpath = sb.toString();
    }
    /**
     * @throws Exception 
     * 
    * @Title: javaCodeToClass
    * @Description: TODO(返回编译之后的类对象，存储内存)
    * @param @param fullClassName
    * @param @param javaCode
    * @param @return
    * @param @throws IllegalAccessException
    * @param @throws InstantiationException    参数
    * @return Class    返回类型
    * @throws
     */
    public Class<?> javaCodeToClass(String fullClassName, String javaCode) throws Exception {
        long start = System.currentTimeMillis();
        Class<?> clazz = null;
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
        ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(diagnostics, null, null));
 
        List<JavaFileObject> jfiles = new ArrayList<JavaFileObject>();
        jfiles.add(new CharSequenceJavaFileObject(fullClassName, javaCode));
 
        List<String> options = new ArrayList<String>();
        options.add("-encoding");
        options.add("UTF-8");
        options.add("-classpath");
        options.add(this.classpath);
 
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, jfiles);
        boolean success = task.call();
 
        if (success) {
            JavaClassObject jco = fileManager.getJavaClassObject();
            DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this.parentClassLoader);
            clazz = dynamicClassLoader.loadClass(fullClassName,jco);
            //instance = clazz.newInstance();
            try {
				dynamicClassLoader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        } else {
            String error = "";
            for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
                error = error + compilePrint(diagnostic);
            }
            throw new Exception("编译出错:"+error);
        }
        long end = System.currentTimeMillis();
        System.out.println("javaCodeToObject use:"+(end-start)+"ms");
        return clazz;
    }
    /**
     * 
    * @Title: compilePrint
    * @Description: TODO(错误返回编译信息)
    * @param @param diagnostic
    * @param @return    参数
    * @return String    返回类型
    * @throws
     */
    private String compilePrint(Diagnostic<?> diagnostic) {
        System.out.println("Code:" + diagnostic.getCode());
        System.out.println("Kind:" + diagnostic.getKind());
        System.out.println("Position:" + diagnostic.getPosition());
        System.out.println("Start Position:" + diagnostic.getStartPosition());
        System.out.println("End Position:" + diagnostic.getEndPosition());
        System.out.println("Source:" + diagnostic.getSource());
        System.out.println("Message:" + diagnostic.getMessage(null));
        System.out.println("LineNumber:" + diagnostic.getLineNumber());
        System.out.println("ColumnNumber:" + diagnostic.getColumnNumber());
        StringBuffer res = new StringBuffer();
        res.append("Code:[" + diagnostic.getCode() + "]\n");
        res.append("Kind:[" + diagnostic.getKind() + "]\n");
        res.append("Position:[" + diagnostic.getPosition() + "]\n");
        res.append("Start Position:[" + diagnostic.getStartPosition() + "]\n");
        res.append("End Position:[" + diagnostic.getEndPosition() + "]\n");
        res.append("Source:[" + diagnostic.getSource() + "]\n");
        res.append("Message:[" + diagnostic.getMessage(null) + "]\n");
        res.append("LineNumber:[" + diagnostic.getLineNumber() + "]\n");
        res.append("ColumnNumber:[" + diagnostic.getColumnNumber() + "]\n");
        return res.toString();
    }
}